package com.xz.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xz.common.exception.ServiceException;
import com.xz.system.domain.SysSeqNum;
import com.xz.system.mapper.SysSeqNumMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @author renyong
 * @date 2023/7/24 13:52
 * @description 业务编号
 */
@Slf4j
@Service
public class SysSeqNumServiceImpl extends ServiceImpl<SysSeqNumMapper,SysSeqNum> {
    /**
     * 参数校验
     */
    @Autowired
    private Validator validator;
    /**
     * 生成编码
     * @param consumer 设置生成编码参数
     * @param length 编号长度
     * @return
     * @author renyong on 2022/7/4 14:20
     */
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public String genCode(Consumer<SysSeqNum> consumer, int length){
        SysSeqNum sysSeqNumQueryVo = new SysSeqNum();
        consumer.accept(sysSeqNumQueryVo);
        if(length<1){
            throw new ServiceException("参数错误");
        }
        Set<ConstraintViolation<SysSeqNum>> constraintViolationSet = validator.validate(sysSeqNumQueryVo);
        if(CollectionUtils.isNotEmpty(constraintViolationSet)){
            String errMsg = constraintViolationSet.stream()
                    .map(ConstraintViolation::getMessage)
                    .collect(Collectors.joining(";","参数错误",""));
            throw new ServiceException(errMsg);
        }
        LambdaQueryWrapper<SysSeqNum> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysSeqNum::getCode,sysSeqNumQueryVo.getCode());
        SysSeqNum sysSeqNum = list(lambdaQueryWrapper).stream().findFirst().orElse(null);
        if(sysSeqNum==null){
            sysSeqNum=new SysSeqNum();
            sysSeqNum.setTenantId(sysSeqNumQueryVo.getTenantId());
            sysSeqNum.setCode(sysSeqNumQueryVo.getCode());
            sysSeqNum.setPrefix(sysSeqNumQueryVo.getPrefix());
            //默认编号不重置
            Optional.ofNullable(sysSeqNumQueryVo.getResetType())
                    .ifPresent(sysSeqNum::setResetType);
            sysSeqNum.setDateFormatStr(sysSeqNumQueryVo.getDateFormatStr());
            sysSeqNum.setCreateTime(new Date());
            sysSeqNum.setUpdateTime(sysSeqNum.getCreateTime());
            sysSeqNum.setRemark(sysSeqNumQueryVo.getRemark());
            save(sysSeqNum);
            //编码 = 前缀 + 时间 + x位顺序号
            return String.format("%s%s%0"+length+"d",sysSeqNum.getPrefix(), sysSeqNum.getDateStr(), sysSeqNum.getCurrentNum());
        }
        LocalDate nowDate = LocalDate.now();
        LocalDate updateTimeLocalDate = sysSeqNum.getUpdateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        sysSeqNum.setCurrentNum(sysSeqNum.getCurrentNum()+1);
        //是否进行重置操作 (按年重置：重置标识==年 && 年不一致) || (按月重置：重置标识==月 && 月不一致) || (按天重置：重置标识==天 && 天不一致)
        boolean resetFlag = (ChronoUnit.YEARS.name().equals(sysSeqNum.getResetType()) && nowDate.getYear()!= updateTimeLocalDate.getYear())
                || (ChronoUnit.MONTHS.name().equals(sysSeqNum.getResetType())&& nowDate.with(TemporalAdjusters.firstDayOfMonth()).toString()
                .equals(updateTimeLocalDate.with(TemporalAdjusters.firstDayOfMonth()).toString()))
                || ChronoUnit.DAYS.name().equals(sysSeqNum.getResetType()) && !nowDate.isEqual(updateTimeLocalDate);
        if(resetFlag){
            sysSeqNum.setCurrentNum(1);
        }
        sysSeqNum.setUpdateTime(new Date());
        sysSeqNum.setTenantId(sysSeqNumQueryVo.getTenantId());
        updateById(sysSeqNum);
        //编码 = 前缀 + 时间 + x位顺序号
        return String.format("%s%s%0"+length+"d",sysSeqNum.getPrefix(), sysSeqNum.getDateStr(), sysSeqNum.getCurrentNum());
    }
    /**
     * 生成合同编号
     * 规则：前缀“CON” + 日期（年月日） + 6位递增数字（次日重新从1开始），示例： CON20220501000004
     * @return
     * @author renyong on 2023-7-24 14:28:46
     */
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public String genContractNo(Long tenantId){
        return this.genCode(sysSeqNum->{
            sysSeqNum.setCode("contract_instance");
            sysSeqNum.setPrefix("CON");
            sysSeqNum.setDateFormatStr("yyyyMMdd");
            sysSeqNum.setResetType(ChronoUnit.DAYS.name());
            sysSeqNum.setTenantId(tenantId);
        },6);
    }
}
